﻿using System;
using AccessControl.Wpf.ViewModels;
using AccessControl.Contracts.Settings;
using System.Windows.Input;
using AccessControl.Contracts.Models;
using AccessControl.Wpf.Commands;
using Action = System.Action;

namespace AccessControl.Wpf.Settings.ViewModels
{
	abstract class SettingsBaseViewModel<T> : ViewModel, ISettingsBaseViewModel where T : IModel
	{
		#region Fields

		T _CurrentItem;
		bool _IsReady = true;
		SettingsState _CurrentState;
		ISettings<T> _SettingsService;

		#endregion

		#region Public Constructor

		public SettingsBaseViewModel(ISettings<T> settingsService)
		{
			SettingsService = settingsService;
		}

		#endregion

		#region Public Properties

		public SettingsState CurrentState
		{
			get { return _CurrentState; }
			set
			{
				if (_CurrentState != value)
				{
					_CurrentState = value;
					NotifyPropertyChanged("CurrentState");
					IsReady = (CurrentState == SettingsState.Ready);
				}
			}
		}

		public ISettings<T> SettingsService
		{
			get { return _SettingsService; }
			private set
			{
				if (_SettingsService != value)
				{
					_SettingsService = value;
					NotifyPropertyChanged("SettingsService");
				}
			}
		}

		public bool IsReady
		{
			get { return _IsReady; }
			set
			{
				if (_IsReady != value)
				{
					_IsReady = value;
					NotifyPropertyChanged("IsReady");
				}
			}
		}
		

		public T CurrentItem
		{
			get { return _CurrentItem; }
			set
			{
				_CurrentItem = value;
				NotifyPropertyChanged("CurrentItem");
				OnCurrentItemChanged();
			}
		}
		
		
		#endregion

		#region Commands

		public ICommand AddItemCommand
		{
			get { return null; }
		}

		public ICommand UpdateItemCommand
		{
			get { return null; }
		}

		public ICommand DeleteItemCommand
		{
			get { return null; }
		}

		public ICommand SetAddModeCommand
		{
			get { return new CommandBase(SetAddMode); }
		}

		public ICommand SetEditModeCommand
		{
			get { return new CommandBase(SetEditMode); }
		}

		public ICommand DeleteCommand
		{
			get { return new CommandBase(Delete); }
		}

		public ICommand SaveCommand
		{
			get { return new CommandBase(Save); }
		}

		public ICommand UndoCommand
		{
			get { return new CommandBase(Undo); }
		}

		#endregion

		#region Abstract Members

		public abstract void AddItem(T item);
		public abstract void EditItem(T item);
		public abstract void DeleteItem(T item);

		public abstract bool IsValidItem(T item);
		public abstract T CreateNewItem();

		#endregion

		#region Virtual Members

		protected virtual void OnCurrentItemChanged() { }
		protected virtual bool IsItemCanBeEdited(T item) { return true; }
		public virtual void LoadSettings()
		{
			SettingsService.Load();
			CurrentItem = default(T);
			CurrentState = SettingsState.Ready;
		}

		#endregion

		#region Private Members

		void SetAddMode()
		{
			T item = CreateNewItem();

			CurrentState = SettingsState.Adding;
			SettingsService.Items.Add(item);
			CurrentItem = item;
		}

		void SetEditMode()
		{
			if (CurrentItem == null)
			{
				MessagingService.Show("Please select item to edit", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			if (IsItemCanBeEdited(CurrentItem))
				CurrentState = SettingsState.Editing;
		}

		void Delete()
		{
			if (CurrentItem == null)
			{
				MessagingService.Show("Please select item to delete", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			if (!IsValidItem(CurrentItem))
				return;

			DeleteItem(CurrentItem);
			SettingsService.Items.Remove(CurrentItem);
			CurrentItem = default(T);
		}

		void Save()
		{
			if (!IsValidItem(CurrentItem))
				return;

			switch (CurrentState)
			{
				case SettingsState.Adding:
					AddItem(CurrentItem);
					break;
				case SettingsState.Editing:
					EditItem(CurrentItem);
					break;
				case SettingsState.Deleting:
					DeleteItem(CurrentItem);
					break;
			}

			CurrentState = SettingsState.Ready;
		}

		void Undo()
		{
			/* Reset the current item */
			CurrentItem = default(T);
			/* Reload the items */
			SettingsService.Load();
			/* And set ready state */
			CurrentState = SettingsState.Ready;
		}		

		#endregion
	}
}
